package cn.techwis.util;


import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;

import cn.hutool.http.Method;
import okhttp3.HttpUrl;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;

import static cn.techwis.common.WxApi.CERTIFICATION;

/**
 * 微信支付签名生成
 */
public class PayOrderSignUtil {


    /**
     * 根据api证书 获取商户私钥
     *
     * @param filename 私钥文件路径  (required)
     * @return
     * @throws IOException
     */
    public static PrivateKey getPrivateKey(String filename) throws IOException, KeyStoreException, NoSuchProviderException, UnrecoverableKeyException, NoSuchAlgorithmException, CertificateException {
        String content = new String(Files.readAllBytes(Paths.get(filename)), "utf-8");
        try {
            String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "")
                    .replace("-----END PRIVATE KEY-----", "")
                    .replaceAll("\\s+", "");

            KeyFactory kf = KeyFactory.getInstance("RSA");
            return kf.generatePrivate(new PKCS8EncodedKeySpec(Base64.decode(privateKey)));

        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("当前Java环境不支持RSA", e);
        } catch (InvalidKeySpecException e) {
            throw new RuntimeException("无效的密钥格式");
        }
    }


    /**
     * 获取微信请求Authorization 头
     *
     * @param requestMethod
     * @param requestBody
     * @param requestUrl
     * @param privateKeyFileName
     * @param mchId
     * @param serial_no
     * @return
     */
    public static final String getAuthorization(String requestMethod, String requestBody, String requestUrl, String privateKeyFileName, String mchId, String serial_no) throws IOException, UnrecoverableKeyException, NoSuchAlgorithmException, NoSuchProviderException, KeyStoreException, CertificateException, SignatureException, InvalidKeyException {
        if (requestMethod.equals(Method.GET.name())) {
            requestBody = null;
        }
        HttpUrl httpurl = HttpUrl.parse(requestUrl);
        //获取当前时间
        long time = System.currentTimeMillis() / 1000;
        //生成随机字符串
        String randomString = RandomUtil.randomString(32);

        String message = buildMessage(requestMethod, httpurl, time, randomString, requestBody);
        String signature = sign(message.getBytes("utf-8"), privateKeyFileName);
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append(CERTIFICATION).append(" ")
                .append("mchid=").append('"').append(mchId).append('"').append(",")
                .append("nonce_str=").append('"').append(randomString).append('"').append(",")
                .append("timestamp=").append('"').append(time).append('"').append(",")
                .append("serial_no=").append('"').append(serial_no).append('"').append(",")
                .append("signature=").append('"').append(signature).append('"').append(",")
        ;
        return stringBuffer.toString();

    }


    public static String sign(byte[] message, String privateKeyFileName) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException, UnrecoverableKeyException, CertificateException, NoSuchProviderException, KeyStoreException, IOException {
        PrivateKey privateKey = getPrivateKey(privateKeyFileName);
        Signature sign = Signature.getInstance("SHA256withRSA");
        sign.initSign(privateKey);
        sign.update(message);
        return Base64.encode(sign.sign());
    }

    static String buildMessage(String method, HttpUrl url, long timestamp, String nonceStr, String body) {
        String canonicalUrl = url.encodedPath();
        if (url.encodedQuery() != null) {
            canonicalUrl += "?" + url.encodedQuery();
        }
        if (StrUtil.isEmpty(body)) {
            body = StrUtil.EMPTY;
        }
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append(method).append("\n")
                .append(canonicalUrl).append("\n")
                .append(timestamp).append("\n")
                .append(nonceStr).append("\n")
                .append(body).append("\n");
        return stringBuffer.toString();
    }


}
